package vn.edu.uit.wifi_transfering;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import protocol.AcceptSendFile;
import protocol.ControlMessage;
import protocol.ErrorMessage;
import protocol.FileInfo;
import protocol.LoginMessage;
import protocol.Message;
import protocol.SuccessMessage;
import protocol.TransferMessage;
import android.content.Context;
import android.os.Environment;
import android.view.Gravity;
import android.widget.Toast;

/**
 * Lop nay dung de ket noi den ServerSocket tren thiet bi khac Do do, thiet bi
 * su dung lop nay se tro thanh Client
 * 
 * @author Le Xuan Vu
 * 
 */

public class TCPClient implements Runnable {

	private Socket socket;
	private static TCPClient client;
	private Thread thread;
	private ObjectOutputStream oos;
	private ObjectInputStream ois;

	private String host = null;
	private int port = 12345;
	private Context mContext;

	public int isConnect = 1;

	public String path = Environment.getExternalStorageDirectory().toString()
			+ "/test.txt";
	public String username = "lexuanvu";
	public String password = "qwerty";

	public TCPClient() {
		//
	}

	public TCPClient(String host, int port, Context mContext) {
		this.host = host;
		this.port = port;
		this.mContext = mContext;
	}

	public static TCPClient getInstance() {
		if (client == null) {
			client = new TCPClient();
		}
		return client;
	}

	public void connectServer() {

		try {
			socket = new Socket();
			SocketAddress sa = new InetSocketAddress(host, port);
			socket.connect(sa, 2000);
			isConnect = 1;
		} catch (IOException e) {

			isConnect = 0;
		}
	}

	public void disconnectServer() {
		try {
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void start() {
		thread.start();
		while (!thread.isAlive()) {
			//
		}
	}

	public void stop() throws IOException {

		if (oos != null) {
			oos.close();
		}

		if (ois != null) {
			ois.close();
		}

		if (socket != null) {
			socket.shutdownInput();
			socket.shutdownOutput();
			socket.close();
		}
	}

	public int loginServer(String username, String password,
			boolean _isAnonymous) throws IOException, ClassNotFoundException {
		oos = new ObjectOutputStream(socket.getOutputStream());
		ois = new ObjectInputStream(socket.getInputStream());

		String pass = md5(password);
		oos.writeObject(new LoginMessage(username, pass, _isAnonymous));

		ControlMessage msg = (ControlMessage) ois.readObject();

		if (msg instanceof SuccessMessage) {
			return 0;
		} else if (msg instanceof ErrorMessage) {
			int error = ((ErrorMessage) msg).error;
			return error;
		}
		return 0;
	}

	public void sendFile() throws IOException {
		File myfile = new File(path);
		byte[] myByteArray = new byte[(int) myfile.length()];
		FileInputStream fis = new FileInputStream(myfile);
		BufferedInputStream bis = new BufferedInputStream(fis);
		bis.read(myByteArray, 0, myByteArray.length);
		OutputStream os = socket.getOutputStream();
		System.out.println("Sending...");
		os.write(myByteArray, 0, myByteArray.length);
		os.flush();
		bis.close();
		fis.close();
		System.out.println("Finish...");
		socket.shutdownOutput();
	}

	public boolean sendFileInfo() throws IOException, ClassNotFoundException {
		double MB = 10 * 1024 * 1024;
		File file = new File(path);
		double sizeFile = file.length();

		if (sizeFile > MB) {
			Toast toast = Toast.makeText(mContext,
					"Size of file is too large !!!", Toast.LENGTH_SHORT);
			toast.setGravity(Gravity.CENTER, 0, 0);
			toast.show();
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return false;
		}

		String fileName = this.path.substring(this.path.lastIndexOf("/") + 1,
				this.path.length());
		String crc = md5ForFile(path);
		System.out.println(fileName + " - " + crc);
		FileInfo fileInfo = new FileInfo(this.username, md5(this.password),
				false, fileName, sizeFile, crc);

		oos = new ObjectOutputStream(socket.getOutputStream());
		ois = new ObjectInputStream(socket.getInputStream());

		oos.writeObject(fileInfo);
		
		TransferMessage msg = (TransferMessage) ois.readObject();
		if (msg instanceof AcceptSendFile) {
			return true;
		} else {
			return false;
		}		
	}

	public void run() {
		//
	}

	private void dispatchMessage(Message msg) {

	}

	public String md5(String string) {
		if (string == null || string.trim().length() < 1) {
			return null;
		}
		try {
			return getMD5(string.getBytes("UTF-8"));
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
	}

	private String getMD5(byte[] source) {
		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			StringBuffer result = new StringBuffer();
			// lay tung 4 bit nhi phan sau do cong voi 1111 roi chuyen sang hexa
			for (byte b : md5.digest(source)) {
				result.append(Integer.toHexString((b & 0xf0) >>> 4)); // lay 4
																		// bit
																		// dau
																		// chuyen
																		// sang
																		// he
																		// hex
				result.append(Integer.toHexString(b & 0x0f));// lay 4 bit sau
																// chuyen sang
																// he hex
			}
			return result.toString();
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage(), e);
		}
	}

	private String md5ForFile(String path) {
		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			FileInputStream fis = new FileInputStream(path);

			byte[] dataBytes = new byte[1024];
			int nread = 0;
			while ((nread = fis.read(dataBytes)) != -1) {
				md5.update(dataBytes, 0, nread);
			}

			StringBuffer result = new StringBuffer();
			for (byte b : md5.digest()) {
				result.append(Integer.toHexString((b & 0xf0) >>> 4));
				result.append(Integer.toHexString(b & 0x0f));
			}

			return result.toString();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return "";
	}
}
